<template>
  <div class="image-upload-component">
    <!-- 上传按钮区域 -->
    <div class="upload-area" v-if="!disabled">
      <el-upload
        ref="uploadRef"
        action="/api/user/upload"
        :headers="headers"
        :data="uploadData"
        name="file"
        :multiple="multiple"
        :accept="accept"
        :on-success="handleSuccess"
        :on-error="handleError"
        :on-progress="handleProgress"
        :on-change="handleChange"
        :before-upload="beforeUpload"
        :before-remove="beforeRemove"
        :auto-upload="autoUpload"
        :file-list="[]"
        :disabled="disabled"
        :limit="limit"
        :on-exceed="handleExceed"
        :show-file-list="false"
        class="upload-container"
      >
        <el-button type="primary" class="upload-button">
          <el-icon><Upload /></el-icon>
          选择文件
        </el-button>
        <template #tip>
          <div class="el-upload__tip">{{ tip }}</div>
        </template>
      </el-upload>
    </div>

    <!-- 图片展示区域 -->
    <div v-if="imageList.length > 0" class="image-gallery">
      <div class="image-container">
        <!-- 图片列表 -->
        <div
          v-for="(image, index) in imageList"
          :key="`${uniqueKey}-${image.id || index}-${index}`"
          class="image-item"
        >
          <el-image
            :src="image.url || image.fileUrl"
            class="gallery-image"
            :fit="fit"
            :preview-src-list="previewList"
            :initial-index="index"
            :preview-teleported="true"
            :hide-on-click-modal="false"
            :lazy="lazy"
            @click="handleImageClick(image, index)"
          >
            <!-- 加载失败显示 -->
            <template #error>
              <div class="image-error">
                <el-icon><Picture /></el-icon>
                <span>{{ errorText }}</span>
              </div>
            </template>
            
            <!-- 加载中显示 -->
            <template #placeholder>
              <div class="image-loading">
                <el-icon class="is-loading"><Loading /></el-icon>
                <span>加载中...</span>
              </div>
            </template>
          </el-image>
          
          <!-- 删除按钮 -->
          <el-button
            v-if="!disabled"
            type="danger"
            size="small"
            circle
            class="delete-btn"
            @click.stop="handleRemove(image, index)"
          >
            <el-icon><Delete /></el-icon>
          </el-button>
        </div>
      </div>
      
      <!-- 图片信息 -->
      <div v-if="showInfo" class="image-info">
        <span class="image-count">共 {{ imageList.length }} 张图片</span>
        <span class="image-tip">{{ tipText }}</span>
      </div>
    </div>
    
    <!-- 无数据提示 -->
    <div v-else-if="!disabled" class="no-data">
      <el-icon><Picture /></el-icon>
      <span>{{ noDataText }}</span>
    </div>

    <!-- 上传进度 -->
    <el-progress
      v-if="uploadProgress > 0 && uploadProgress < 100"
      :percentage="uploadProgress"
      :status="uploadStatus"
      class="upload-progress"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Upload, Delete, Picture, Loading } from '@element-plus/icons-vue'
import type { UploadUserFile, UploadRawFile } from 'element-plus'
import { showError, showSuccess, showWarning } from '@/utils/message'

// 图片信息接口
export interface ImageInfo {
  id?: string | number
  url?: string
  fileUrl?: string
  fileName?: string
  fileSize?: number
  [key: string]: any
}

// 组件属性
interface Props {
  /** 图片列表 */
  modelValue?: ImageInfo[]
  /** 上传类型 */
  uploadType?: string
  /** 上传来源 */
  uploadSource?: string
  /** 是否支持多文件 */
  multiple?: boolean
  /** 接受的文件类型 */
  accept?: string
  /** 是否自动上传 */
  autoUpload?: boolean
  /** 是否禁用 */
  disabled?: boolean
  /** 最大上传数量 */
  limit?: number
  /** 提示文字 */
  tip?: string
  /** 文件大小限制（MB） */
  maxSize?: number
  /** 允许的文件类型 */
  allowedTypes?: string[]
  /** 图片适应方式 */
  fit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
  /** 是否懒加载 */
  lazy?: boolean
  /** 是否显示图片信息 */
  showInfo?: boolean
  /** 错误提示文本 */
  errorText?: string
  /** 无数据提示文本 */
  noDataText?: string
  /** 提示文本 */
  tipText?: string
  /** 唯一标识符 */
  uniqueKey?: string
}

// 默认属性值
const props = withDefaults(defineProps<Props>(), {
  modelValue: () => [],
  uploadType: 'OTHER',
  uploadSource: 'WEB',
  multiple: false,
  accept: 'image/*',
  autoUpload: true,
  disabled: false,
  limit: 10,
  tip: '请选择要上传的图片',
  maxSize: 10,
  allowedTypes: () => ['jpg', 'jpeg', 'png', 'gif'],
  fit: 'cover',
  lazy: true,
  showInfo: true,
  errorText: '加载失败',
  noDataText: '暂无图片',
  tipText: '点击图片可预览大图',
  uniqueKey: 'image-upload'
})

// 事件定义
const emit = defineEmits<{
  'update:modelValue': [images: ImageInfo[]]
  'on-success': [response: any, file: any, fileList: ImageInfo[]]
  'on-error': [error: Error, file: any, fileList: ImageInfo[]]
  'on-progress': [event: any, file: any, fileList: ImageInfo[]]
  'on-change': [file: any, fileList: ImageInfo[]]
  'on-remove': [file: any, fileList: ImageInfo[]]
  'on-image-click': [image: ImageInfo, index: number]
}>()

// 响应式数据
const uploadRef = ref()
const uploadProgress = ref(0)
const uploadStatus = ref<'success' | 'exception' | ''>('')

// 计算属性
const imageList = computed({
  get: () => props.modelValue || [],
  set: (value) => emit('update:modelValue', value)
})

const headers = computed(() => {
  const token = localStorage.getItem('token')
  return {
    Authorization: token ? `Bearer ${token}` : ''
  }
})

const uploadData = computed(() => ({
  uploadType: props.uploadType,
  uploadSource: props.uploadSource
}))

const previewList = computed(() => {
  return imageList.value.map(image => image.url || image.fileUrl).filter(Boolean)
})

// 方法定义
const beforeUpload = (rawFile: UploadRawFile) => {
  if (props.maxSize && rawFile.size / 1024 / 1024 > props.maxSize) {
    showError(`文件大小不能超过 ${props.maxSize}MB`)
    return false
  }

  if (props.allowedTypes.length > 0) {
    const fileName = rawFile.name
    const fileExt = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase()
    const isTypeAllowed = props.allowedTypes.some(type => fileExt === type)
    
    if (!isTypeAllowed) {
      showError(`只允许上传 ${props.allowedTypes.join(', ')} 格式的文件`)
      return false
    }
  }

  uploadProgress.value = 0
  uploadStatus.value = ''
  return true
}

const beforeRemove = (file: any) => {
  return ElMessageBox.confirm('确定要删除这个图片吗?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => true).catch(() => false)
}

const handleSuccess = (response: any, file: any) => {
  uploadProgress.value = 100
  uploadStatus.value = 'success'

  if (response && response.data) {
    const newImage: ImageInfo = {
      id: response.data.id,
      url: response.data.fileUrl,
      fileUrl: response.data.fileUrl,
      fileName: response.data.fileName,
      fileSize: response.data.fileSize
    }
    
    const newImageList = [...imageList.value, newImage]
    emit('update:modelValue', newImageList)
    emit('on-success', response, newImage, newImageList)
    showSuccess('上传成功')
  }

  setTimeout(() => {
    uploadProgress.value = 0
    uploadStatus.value = ''
  }, 2000)
}

const handleError = (error: Error, file: any) => {
  uploadProgress.value = 100
  uploadStatus.value = 'exception'
  emit('on-error', error, file, imageList.value)
  showError('上传失败')

  setTimeout(() => {
    uploadProgress.value = 0
    uploadStatus.value = ''
  }, 2000)
}

const handleProgress = (event: any, file: any) => {
  uploadProgress.value = Math.round(event.percent || 0)
  emit('on-progress', event, file, imageList.value)
}

const handleChange = (file: any) => {
  emit('on-change', file, imageList.value)
}

const handleExceed = (files: any) => {
  showWarning(`最多只能上传 ${props.limit} 个文件`)
}

const handleImageClick = (image: ImageInfo, index: number) => {
  if (props.disabled) return
  emit('on-image-click', image, index)
}

const handleRemove = (image: ImageInfo, index: number) => {
  const newImageList = [...imageList.value]
  newImageList.splice(index, 1)
  emit('update:modelValue', newImageList)
  emit('on-remove', image, newImageList)
}

// 暴露方法给父组件
defineExpose({
  /** 清空文件列表 */
  clearFiles: () => {
    emit('update:modelValue', [])
  },
  /** 获取图片列表 */
  getImageList: () => imageList.value,
  /** 获取预览列表 */
  getPreviewList: () => previewList.value
})
</script>

<style lang="scss" scoped>
.image-upload-component {
  width: 100%;
  
  .upload-area {
    margin-bottom: 16px;
    
    .upload-button {
      width: 100%;
      height: 40px;
    }
  }
  
  .image-gallery {
    .image-container {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      margin-bottom: 8px;
      position: relative;

      .image-item {
        position: relative;
        display: inline-block;

        .gallery-image {
          width: 80px;
          height: 80px;
          border-radius: 8px;
          border: 1px solid #e4e7ed;
          cursor: pointer;
          transition: all 0.3s ease;
          overflow: hidden;

          &:hover {
            transform: scale(1.05);
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
          }

          &:active {
            transform: scale(0.98);
          }
        }

        .delete-btn {
          position: absolute;
          top: -8px;
          right: -8px;
          width: 20px;
          height: 20px;
          padding: 0;
          font-size: 12px;
          z-index: 10;
        }
      }

      .image-error {
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        background: #f5f7fa;
        color: #909399;
        font-size: 12px;

        .el-icon {
          font-size: 20px;
          margin-bottom: 4px;
        }
      }

      .image-loading {
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        background: #f5f7fa;
        color: #909399;
        font-size: 12px;

        .el-icon {
          font-size: 20px;
          margin-bottom: 4px;
        }
      }
    }

    .image-info {
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: 12px;
      color: #909399;

      .image-count {
        font-weight: 500;
      }

      .image-tip {
        color: #409eff;
        cursor: pointer;

        &:hover {
          text-decoration: underline;
        }
      }
    }
  }

  .no-data {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 20px;
    color: #c0c4cc;
    font-style: italic;
    border: 1px dashed #d9d9d9;
    border-radius: 8px;
    background: #fafafa;

    .el-icon {
      font-size: 24px;
      margin-bottom: 8px;
    }
  }

  .upload-progress {
    margin-top: 8px;
  }
}
</style>
